﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using System.IO;
using AfterlifeLib.Projectiles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace AfterlifeLib.Particles
{
    public class ParticleManager
    {
        const int MAX_PARTICLES = 1000;

        Dictionary<string, ParticleSettings> particleSettings = new Dictionary<string,ParticleSettings>();
        Dictionary<string, Texture2D> particleTextures = new Dictionary<string, Texture2D>();
        Particle[] particles;
        Queue<Particle> inactiveParticles;

        Random random = new Random();

        public int ActiveProjectiles
        {
            get { return particles.Length - inactiveParticles.Count; }
        }

        public int InactiveProjectiles
        {
            get { return inactiveParticles.Count; }
        }

        public ParticleManager() { }

        public void Initialize()
        {
            particles = new Particle[MAX_PARTICLES];
            inactiveParticles = new Queue<Particle>(MAX_PARTICLES);

            for (int i = 0; i < particles.Length; i++)
            {
                particles[i] = new Particle();
                inactiveParticles.Enqueue(particles[i]);
            }
        }

        public void Update(GameTime gameTime)
        {
            float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

            foreach (Particle p in particles)
            {
                if (p.Active)
                {
                    p.Update(delta);

                    if (!p.Active)
                    {
                        inactiveParticles.Enqueue(p);
                    }
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch, Camera2D camera)
        {
            spriteBatch.Begin(SpriteBlendMode.Additive);
            {
                foreach (Particle p in particles)
                {
                    if (!p.Active)
                        continue;

                    p.Draw(spriteBatch, camera);
                }
            }
            spriteBatch.End();
        }

        public void AddParticleSettings(ContentManager content, string fileName)
        {
            ParticleSettings settings = content.Load<ParticleSettings>(fileName);
            particleSettings.Add(Path.GetFileNameWithoutExtension(fileName), settings);

            if (!particleTextures.ContainsKey(settings.textureName))
            {
                Texture2D texture = content.Load<Texture2D>(settings.textureName);
                particleTextures.Add(settings.textureName, texture);
            }
        }

        public void AddParticles(string particleSettingsName, Vector2 position)
        {
            if (!particleSettings.ContainsKey(particleSettingsName))
                return;

            ParticleSettings settings = particleSettings[particleSettingsName];

            int numParticles = RandBetween(settings.minParticles, settings.maxParticles);
            for (int i = 0; i < numParticles; i++)
            {
                if (inactiveParticles.Count <= 0)
                    break;

                Particle p = inactiveParticles.Dequeue();

                p.Initialize(
                    particleTextures[settings.textureName], 
                    position, 
                    settings.color,
                    RandBetween(settings.minSpeed, settings.maxSpeed), 
                    RandBetween(settings.minAngle, settings.maxAngle), 
                    RandBetween(settings.minScale, settings.maxScale), 
                    RandBetween(settings.minLifeTime, settings.maxLifeTime));
            }
        }

        public void AddProjectileDestroyedEvent(ProjectileManager pm)
        {
            pm.ProjectileDestroyedEvent += OnProjectileDestroyed;
        }

        public void RemoveProjectileDestroyedEvent(ProjectileManager pm)
        {
            pm.ProjectileDestroyedEvent -= OnProjectileDestroyed;
        }

        public void OnProjectileDestroyed(object sender, ProjectileDestroyedEventArgs e)
        {
            AddParticles(e.ParticleSettings, e.Position);
        }

        public int RandBetween(int min, int max)
        {
            return (int)MathHelper.Lerp(min, max, (float)random.NextDouble());
        }

        public float RandBetween(float min, float max)
        {
            return MathHelper.Lerp(min, max, (float)random.NextDouble());
        }
    }
}
